package model;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import view.GameMenu;

import linkedList.LinkedList;
import exceptions.*;

public class HighScoresFileModel implements IHighScoresModel {

	/**
	 * Encapsulates info about a single high score
	 * 
	 * @author Dev-1
	 *
	 */
	private class HighScore {
		private String playerName = "Gosho";
		private int score;
		
		private HighScore(String playerName, int score) {
			setPlayerName(playerName);
			setScore(score);
		}

		public String getPlayerName() {
			return playerName;
		}

		public void setPlayerName(String playerName) {
			if ( playerName != null )
				this.playerName = playerName;
		}

		public int getScore() {
			return score;
		}

		public void setScore(int score) {
			if ( score >= 0 )
				this.score = score;
		}
	}

	
	
	private static final String NEW_LINE = System.getProperty("line.separator");
	private static final int MAXIMUM_NUMBER_OF_HIGHSCORES = 10;
	private static final int MAXIMUM_DIGITS_OF_SCORE = 2;

	private LinkedList highestScoresList;
	private File[] highestScoresFiles;
	private File currentFileWithHighScores;
	private static final File[] highscoreFiles = {
			new File("highscores_5x5.txt"), 
			new File("highscores_7x7.txt"),
			new File("highscores_9x9.txt") 
	};

	public HighScoresFileModel() {
		highestScoresList = new LinkedList();
		highestScoresFiles = new File[0];
	}

	public void setBoardSize() {

	}

	/**
	 * writes the high scores loaded in the linked list to a file
	 * 
	 * @param highscoresFile
	 */
	public void writeHighScoresList() {
		File highscoresFile = currentFileWithHighScores;
		BufferedWriter writer = null;
		try {
			writer = new BufferedWriter(new FileWriter(highscoresFile));
			for (int i = 0; i < highestScoresList.getSize(); i++) {
				try {
					writer.write(highestScoresList.get(i).toString());
					if (i != highestScoresList.getSize() - 1) {
						writer.write(System.getProperty("line.separator"));
					}
				} catch (LinkedListIndexException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (writer != null) {
				try {
					writer.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

	}

	/**
	 * loads the linked list with higshcores from a file
	 * 
	 * @param highscoresFile
	 */
	public void getHighScoresList() {
		File highscoresFile = currentFileWithHighScores;
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(highscoresFile));
			String textLine = reader.readLine();

			while (textLine != null) {
				try {
					highestScoresList.add(textLine);
					textLine = reader.readLine();
				} catch (InvalidDataParameterException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

	/**
	 * 
	 * @return string, representing all high scores in the game
	 */
	public String allHighscoresToString() {

		String allHighscores = "";
		for (int i = 0; i < highestScoresFiles.length; i++) {
			allHighscores += "Highscores for game "
					+ GameMenu.getAvailableSizeAt(i) + "x"
					+ GameMenu.getAvailableSizeAt(i) + ":" + NEW_LINE;

			setCurrentFileWithHighScores(highestScoresFiles[i]);
			getHighScoresList();
			allHighscores += getDataAsString() + NEW_LINE;
		}
		return allHighscores;

	}

	/**
	 * 
	 * @param highscoresFile
	 * @return a string, representing high scores in a file
	 */
	public String getDataAsString() {
		String highscoresText = "";
		for (int i = 0; i < highestScoresList.getSize(); i++) {
			try {
				highscoresText += "\t" + highestScoresList.get(i) + NEW_LINE;
			} catch (LinkedListIndexException e) {
				e.printStackTrace();
			}
		}

		return highscoresText;

	}

	/*
	 * Sets the current file for high scores. Cases depend on the available
	 * sizes in the game menu!!
	 */
	public void setBoardSize(BoardSize boardSize) {
		switch (boardSize) {
		case SMALL:
			currentFileWithHighScores = highestScoresFiles[0];
			break;
		case MEDIUM:
			currentFileWithHighScores = highestScoresFiles[1];
			break;
		case LARGE:
			currentFileWithHighScores = highestScoresFiles[2];
			break;
		default:
			System.err
					.println("Can't find highscore file for the given board size!");
		}

	}

	public File getCurrentFileWithHighScores() {
		return currentFileWithHighScores;
	}

	public void setCurrentFileWithHighScores(File currentFileWithHighScores) {
		this.currentFileWithHighScores = currentFileWithHighScores;
	}
	
	/**
	 * Saving high scores in a file, if there is one. Returns 
	 * @param player
	 * @param boardSize
	 * @return if the player has made it to the high scores
	 */
	public boolean saveHighScores(String playerName, int score) {
		getHighScoresList();
		
		String newScoreLine = "Name: " + playerName + " -> Score: "	+ score;
		
		boolean isPlayerIntoHighScoresList = updateHighScoresList(score, newScoreLine);
		
		writeHighScoresList();
		
		return isPlayerIntoHighScoresList;

	}
	
	/*
	 * returns if the given score has made it to the high scores
	 */
	private boolean updateHighScoresList(int newScore,
			String newScoreLine) {

		if (!highestScoresList.contains(newScoreLine)) {
			boolean inserted = false;
			for (int i = 0; i < highestScoresList.getSize(); i++) {
				try {
					String scoreLine = highestScoresList.get(i).toString();
					String scoreText = scoreLine.substring(scoreLine.length()
							- MAXIMUM_DIGITS_OF_SCORE, scoreLine.length());
					int score = Integer.parseInt(scoreText.replaceAll("[^0-9]",
							""));
					if (newScore >= score) {
						try {
							highestScoresList.insertAt(i, newScoreLine);
							inserted = true;
						} catch (InvalidDataParameterException e) {
							e.printStackTrace();
						}
						break;
					}
				} catch (LinkedListIndexException e) {
					e.printStackTrace();
				}
			}
			if (!inserted) {
				try {
					highestScoresList.add(newScoreLine);
				} catch (InvalidDataParameterException e) {
					e.printStackTrace();
				}
			}
			if (highestScoresList.getSize() > MAXIMUM_NUMBER_OF_HIGHSCORES) {
				try {
					highestScoresList.remove(highestScoresList.getSize() - 1);
				} catch (LinkedListIndexException e) {
					e.printStackTrace();
				}
			}
		}
		if (highestScoresList.contains(newScoreLine)) {
			return true;
		}
		return false;
	}
	
}
